﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Data;
using System.Threading;
using CommonUtils;

namespace NSpring.Logging
{
	namespace Singleton
	{
		public class Logger
		{
			#region statics
			private static Logger Instance(Level inLevel)
			{
				foreach (Logging.Logger child in _CompositeLogger.Children)
					child.Level = inLevel;
				return _Instance;
			}

			public static int FrameOffset { get; set; }			
			public static void AddChildren(params Logging.Logger[] inChildren)
			{
				foreach (Logging.Logger child in inChildren)
					_CompositeLogger.AddChild(child);
			}

			public static Logger ForDebug		{ get { return Instance(Level.Debug); } }
			public static Logger ForVerbose		{ get { return Instance(Level.Verbose); } }
			public static Logger ForConfig		{ get { return Instance(Level.Config); } }
			public static Logger ForInfo		{ get { return Instance(Level.Info); } }
			public static Logger ForWarning		{ get { return Instance(Level.Warning); } }
			public static Logger ForException	{ get { return Instance(Level.Exception); } }
			public static Logger ForAll			{ get { return Instance(Level.All); } }
			public static Logger ForNone		{ get { return Instance(Level.None); } }

			public static void AddLogger(string name, Logging.Logger logger)
			{
				Logging.Logger.registry.AddLogger(name, logger);
			}
			public static void RemoveLogger(string name)
			{
				Logging.Logger.registry.RemoveLogger(name);
			}
			public static void RemoveLogger(Logging.Logger logger)
			{
				Logging.Logger.registry.RemoveLogger(logger);
			}
			public static void OpenLoggers()
			{
				Logging.Logger.registry.Open();
			}
			public static void CloseLoggers()
			{
				Logging.Logger.registry.Close();
			}
			public static Logging.Logger GetLogger(string name)
			{
				return Logging.Logger.registry.GetLogger(name);
			}
			public static Logging.Logger[] Loggers { get { return Logging.Logger.registry.Loggers; } }

			public static string[] LoggerNames { get { return Logging.Logger.registry.LoggerNames; } }

			public static bool IsRegistryCaseSensitive
			{
				get { return Logging.Logger.registry.IsCaseSensitive; }
				set { Logging.Logger.registry.IsCaseSensitive = value; }
			}
			public static Logging.Loggers.CompositeLogger CreateCompositeLogger(params Logging.Logger[] inLoggers)
			{
				return new Logging.Loggers.CompositeLogger(inLoggers);
			}
			public static Logging.Loggers.ConsoleLogger CreateConsoleLogger()
			{
				return new Logging.Loggers.ConsoleLogger();
			}
			public static Logging.Loggers.ConsoleLogger CreateConsoleLogger(string _pattern)
			{
				return new Logging.Loggers.ConsoleLogger(_pattern);
			}
			public static Logging.Loggers.DatabaseLogger CreateDatabaseLogger(IDbConnection _connection, string _sqlPattern)
			{
				return new Logging.Loggers.DatabaseLogger(_connection, _sqlPattern);
			}
			public static Logging.Loggers.DebugLogger CreateDebugLogger()
			{
				return new Logging.Loggers.DebugLogger();
			}
			public static Logging.Loggers.EmailLogger CreateEmailLogger(string _from, string _to, string _cc, string _bcc, string _subject, string _body)
			{
				return new Logging.Loggers.EmailLogger(_from, _to, _cc, _bcc, _subject, _body);
			}
			public static Logging.Loggers.EmailLogger CreateEmailLogger(string _serverAddress, string _from, string _to, string _cc, string _bcc, string _subject, string _body)
			{
				return new Logging.Loggers.EmailLogger(_serverAddress, _from, _to, _cc, _bcc, _subject, _body);
			}
			public Logging.Loggers.EmailLogger CreateEmailLogger(string _from, string _to)
			{
				return new Logging.Loggers.EmailLogger(_from, _to);
			}
			public Logging.Loggers.EmailLogger CreateEmailLogger(string _serverAddress, string _from, string _to)
			{
				return new Logging.Loggers.EmailLogger(_serverAddress, _from, _to);
			}
			public static Logging.Loggers.FileLogger CreateFileLogger(string _filePath)
			{
				return new Logging.Loggers.FileLogger(_filePath);
			}
			public static Logging.Loggers.FileLogger CreateFileLogger(string _filePath, string _outputPattern)
			{
				return new Logging.Loggers.FileLogger(_filePath, _outputPattern);
			}
			public static Logging.Loggers.MessageQueueLogger CreateMessageQueueLogger(string _serverAddress, string _queueName, string _summaryPattern)
			{
				return new Logging.Loggers.MessageQueueLogger(_serverAddress, _queueName, _summaryPattern);
			}
			public static Logging.Loggers.MessageQueueLogger CreateMessageQueueLogger(string _serverAddress, string _queueName)
			{
				return new Logging.Loggers.MessageQueueLogger(_serverAddress, _queueName);
			}
			public static Logging.Loggers.MessageQueueLogger CreateMessageQueueLogger(string _queueName)
			{
				return new Logging.Loggers.MessageQueueLogger(_queueName);
			}
			public static Logging.Loggers.StreamLogger CreateStreamLogger(Stream _stream)
			{
				return new Logging.Loggers.StreamLogger(_stream);
			}
			public static Logging.Loggers.TraceLogger CreateTraceLogger()
			{
				return new Logging.Loggers.TraceLogger();
			}
			public static Logging.Loggers.WindowsEventLogger CreateWindowsEventLogger(string _eventLogSource, string _eventLogName)
			{
				return new Logging.Loggers.WindowsEventLogger(_eventLogSource, _eventLogName);
			}
			#endregion statics

			#region ctors
			protected Logger()
			{
				FrameOffset = 2;
			}
			#endregion ctors

			#region properties
			public Level Level
			{
				get { return _CompositeLogger.Level; }
				set { _CompositeLogger.Level = value; }
			}
			public bool IsOpen
			{
				get { return _CompositeLogger.IsOpen; }
			}
			public bool IsBufferingEnabled
			{
				get { return _CompositeLogger.IsBufferingEnabled; }
				set { _CompositeLogger.IsBufferingEnabled = value; }
			}
			public bool IsExceptionAutoFlushEnabled
			{
				get { return _CompositeLogger.IsExceptionAutoFlushEnabled; }
				set { _CompositeLogger.IsExceptionAutoFlushEnabled = value; }
			}
			public static bool IsExceptionAutoFlushEnabledByDefault
			{
				get { return Logging.Logger.IsExceptionAutoFlushEnabledByDefault; }
			}
			public int BufferSize
			{
				get { return _CompositeLogger.BufferSize; }
				set { _CompositeLogger.BufferSize = value; }
			}
			public int MaximumBufferSize
			{
				get { return _CompositeLogger.MaximumBufferSize; }
				set { _CompositeLogger.MaximumBufferSize = value; }
			}
			public int BufferCount
			{
				get { return _CompositeLogger.BufferCount; }
			}
			public int AutoFlushInterval
			{
				get { return _CompositeLogger.AutoFlushInterval; }
				set { _CompositeLogger.AutoFlushInterval = value; }
			}
			public ThreadPriority ThreadPriority
			{
				get { return _CompositeLogger.ThreadPriority; }
				set { _CompositeLogger.ThreadPriority = value; }
			}
			#endregion properties

			#region methods
			public static void HandleException(object sender, ExceptionEventArgs e)
			{
				Logger.ForAll.Log(e.Exception);
			}
			public static void HandleMessage(object sender, MessageEventArgs e)
			{
				if (e.Level >= e.Threshold)
					Logger.ForAll.Log(e.Message);
			}

			public Logger Log(string _message)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message)); return this;
			}
			public Logger Log(string _message, string _category)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _category); return this;
			}
			public Logger Log(Level _level, string _message)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message)); return this;
			}
			public Logger Log(Level _level, string _message, string _category)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _category); return this;
			}
			public Logger Log(string _message, string _category, string _code)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _category, _code); return this;
			}
			public Logger Log(string _message, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _category, _code, _id); return this;
			}
			public Logger Log(Level _level, string _message, string _category, string _code)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _category, _code); return this;
			}
			public Logger Log(Level _level, string _message, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _category, _code, _id); return this;
			}
			public Logger Log(string _message, object _data)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _data); return this;
			}
			public Logger Log(string _message, object _data, string _category)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _data, _category); return this;
			}
			public Logger Log(Level _level, string _message, object _data)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _data); return this;
			}
			public Logger Log(Level _level, string _message, object _data, string _category)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _data, _category); return this;
			}
			public Logger Log(string _message, object _data, string _category, string _code)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _data, _category, _code); return this;
			}
			public Logger Log(string _message, object _data, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(AddNewLinesAndTabsToMessage(_message), _data, _category, _code, _id); return this;
			}
			public Logger Log(Level _level, string _message, object _data, string _category, string _code)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _data, _category, _code); return this;
			}
			public Logger Log(Level _level, string _message, object _data, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(_level, AddNewLinesAndTabsToMessage(_message), _data, _category, _code, _id); return this;
			}
			public Logger Log(object _data)
			{
				_CompositeLogger.Log(_data); return this;
			}
			public Logger Log(object _data, string _category)
			{
				_CompositeLogger.Log(_data, _category); return this;
			}
			public Logger Log(Level _level, object _data)
			{
				_CompositeLogger.Log(_level, _data); return this;
			}
			public Logger Log(Level _level, object _data, string _category)
			{
				_CompositeLogger.Log(_level, _data, _category); return this;
			}
			public Logger Log(object _data, string _category, string _code)
			{
				_CompositeLogger.Log(_data, _category, _code); return this;
			}
			public Logger Log(object _data, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(_data, _category, _code, _id); return this;
			}
			public Logger Log(Level _level, object _data, string _category, string _code)
			{
				_CompositeLogger.Log(_level, _data, _category, _code); return this;
			}
			public Logger Log(Level _level, object _data, string _category, string _code, string _id)
			{
				_CompositeLogger.Log(_level, _data, _category, _code, _id); return this;
			}
			public Logger Log(Exception _exception)
			{
				_CompositeLogger.Log(_exception); return this;
			}
			public Logger Log(Exception _exception, string _id)
			{
				_CompositeLogger.Log(_exception, _id); return this;
			}
			public Logger Open()
			{
				_CompositeLogger.Open(); return this;
			}
			public Logger Close()
			{
				_CompositeLogger.Close(); return this;
			}

			public Logger LogMethodInfo()
			{
				LogMethodInfo("", FrameOffset);
				return Instance(_CompositeLogger.Level);
			}
			public Logger LogMethodInfo(string inText)
			{
				LogMethodInfo(inText, FrameOffset);
				return Instance(_CompositeLogger.Level);
			}
			public Logger LogMethodInfo(int inFrameOffset)
			{
				LogMethodInfo("", inFrameOffset);
				return Instance(_CompositeLogger.Level);
			}
			public Logger LogMethodInfo(string inText, int inFrameOffset)
			{
				StackFrame sf = new StackTrace(true).GetFrame(inFrameOffset);
				_CompositeLogger.Log(string.Format("{0} {1}::{2} in {3} at [line:{4},char:{5}]", new object[] { inText, sf.GetMethod().DeclaringType.Name, sf.GetMethod().Name, Path.GetFileName(sf.GetFileName()), sf.GetFileLineNumber(), sf.GetFileColumnNumber() }));

				return Instance(_CompositeLogger.Level);
			}
			public Logger LogProcessInfo()
			{
				LogProcessInfo(Process.GetCurrentProcess());
				return Instance(_CompositeLogger.Level);
			}
			public Logger LogProcessInfo(Process inProcess)
			{
				_CompositeLogger.Log(FormatMyProcess(inProcess));
				return Instance(_CompositeLogger.Level);
			}
			private static string FormatMyProcess(Process inProcess)
			{
				string str = "";
				if (inProcess != null)
				{
					str += "\nProcess Info:";
					str += "\n{";
					str += "\n\tMemory: " + inProcess.WorkingSet64 / 1024 + "k";
					str += "\n\tPeak: " + inProcess.PeakWorkingSet64 / 1024 + "k";
					str += "\n\tThreads: " + inProcess.Threads.Count;
					str += "\n\tMainModule: " + Path.GetFileNameWithoutExtension(inProcess.MainModule.FileName) + " version: " + inProcess.MainModule.FileVersionInfo.FileVersion;
					str += "\n}";
				}
				return str;
			}
			public Logger NewLine()
			{
				NewLine(1);
				return Instance(_CompositeLogger.Level);
			}
			public Logger NewLine(uint inNumber)
			{
				string newlines = (inNumber > 0) ? "\n" : "";
				for (int i = 1; i < inNumber; ++i)
					newlines += "\n";
				_NewLinesAndTabs += newlines;
				return Instance(_CompositeLogger.Level);
			}
			public Logger Tab()
			{
				Tab(1);
				return Instance(_CompositeLogger.Level);
			}
			public Logger Tab(uint inNumber)
			{
				string tabs = (inNumber > 0) ? "\t" : "";
				for (int i = 1; i < inNumber; ++i)
					tabs += "\t";
				_NewLinesAndTabs += tabs;
				return Instance(_CompositeLogger.Level);
			}
			public void AddToNewLinesAndTabs(char inChar)
			{
				if (inChar == '\n' || inChar == '\t')
					_NewLinesAndTabs += inChar;
			}
			public string UseNewLinesAndTabs()
			{
				string temp = _NewLinesAndTabs;
				_NewLinesAndTabs = "";
				return temp;
			}
			public string AddNewLinesAndTabsToMessage(string _message)
			{
				return UseNewLinesAndTabs() + _message;
			}
			#endregion methods

			#region fields
			private static readonly Logging.Logger _CompositeLogger = new Loggers.CompositeLogger();
			private static readonly Logger _Instance = new Logger();
			private static string _NewLinesAndTabs = "";
			#endregion fields
		}
	}
}
